package com.gao.security.verificationcode.validatecode;


import com.gao.security.verificationcode.base.BaseCode;
import com.gao.security.verificationcode.base.BaseCodeOperationManager;
import com.gao.security.verificationcode.base.BaseVerificationCodeHandler;
import com.gao.security.verificationcode.base.KeyGenerationStrategy;
import com.gao.security.verificationcode.common.vo.VerficationCodeGenerationDto;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.Map;
import java.util.concurrent.*;

/**
 * <p>
 *     抽象模板验证码渲染
 * </p>
 *
 * @author GaoShuangWen
 */
public abstract class AbstractVerificationCodeHandler implements BaseVerificationCodeHandler {

    private ExecutorService singleThreadPool =this.threadPoolInstance();
    private BaseCodeOperationManager codeOperationStrategy;
    private KeyGenerationStrategy generationStrategy;

    public AbstractVerificationCodeHandler( BaseCodeOperationManager codeOperationStrategy) {
        this.codeOperationStrategy = codeOperationStrategy;
    }

    @Override
    public BaseCode render(VerficationCodeGenerationDto dto) {
        // 获取baseCode
        String code=getCode();
        BaseCode baseCode = new BaseCode(code, generationStrategy.key(dto), 1);
        // 存储验证码
        singleThreadPool.execute(() ->
                codeOperationStrategy.saveCode(baseCode)
        );
        return baseCode;
    }

    /**
     * 获取BaseCode
     * @return
     */
    public abstract String getCode();

    public void setCodeOperationStrategy(BaseCodeOperationManager codeOperationStrategy) {
        this.codeOperationStrategy = codeOperationStrategy;
    }


    public void setGenerationStrategy(KeyGenerationStrategy generationStrategy) {
        this.generationStrategy = generationStrategy;
    }

    private ExecutorService threadPoolInstance() {
        ThreadFactory threadFactory = new ThreadFactoryBuilder().build();
        return new ThreadPoolExecutor(10, 10, 30L,
                TimeUnit.SECONDS, new ArrayBlockingQueue<>(10), threadFactory, new ThreadPoolExecutor.AbortPolicy());
    }

    /**
     * 提供线程池扩展
     * @param singleThreadPool
     */
    public void setSingleThreadPool(ExecutorService singleThreadPool) {
        this.singleThreadPool = singleThreadPool;
    }
}
